home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / wvnsrc75.zip / WVHEADER.C < prev    next >
Text File  |  1992-11-09  |  22KB  |  877 lines

  1. /* --- WVHEADER.C ---------------------------------------------
  2.  *
  3.  *  This file contains the code necessary to create the initial skeleton
  4.  *  version of an article, which will be edited by the user.
  5.  *
  6.  *  Mark Riordan   24-JAN-1990
  7.  */
  8.  
  9.  
  10. #include "windows.h"
  11. #include "wvglob.h"
  12. #include "winvn.h"
  13. #ifndef MAC
  14. #include "winundoc.h"
  15. #include <ctype.h>
  16. #include <time.h>
  17. #endif
  18.  
  19.  
  20. #define MAXHEADERLINE 256
  21.  
  22.  
  23. BOOL (*PostHeaderFuncs[])(TypDoc * Doc, char *Buf, long int BufLen) =
  24. {
  25.   MakeArtHeaderFrom,
  26.     MakeArtHeaderNewsgroups,
  27.     MakeArtHeaderSubject,
  28. /* MakeArtHeaderMessageID, */
  29. /* MakeArtHeaderDate,      */
  30.     MakeArtHeaderReferences,
  31.     MakeArtHeaderOrganization,
  32. /*    MakeArtHeaderNewsreader, */
  33.     NULL
  34. };
  35.  
  36. BOOL (*MailHeaderFuncs[])(TypDoc * Doc, char *Buf, long int BufLen) =
  37. {
  38.   MakeArtHeaderTo,
  39.     MakeArtHeaderFrom,
  40.     MakeArtHeaderSubject,
  41.     MakeArtHeaderOrganization,
  42.     NULL
  43. };
  44.  
  45. /*--- function GetHeaderLine -------------------------------------------
  46.  *
  47.  *  Given a document, get a line from the header portion of that document
  48.  *  whose prefix matches a given prefix.  Prefix = first word in line.
  49.  *  For instance, you might call this routine to say "Get the 'Subject:'"
  50.  *  line from this document.
  51.  *
  52.  *    Entry    Doc      points to the document whose header we are scanning.
  53.  *                      The header is all the lines up to the first blank line.
  54.  *             Prefix   is the character string which will identify the
  55.  *                      line we are seeking.  It is the first word
  56.  *                      (blank-delimited) in a line in the header.
  57.  *             BufLen   is the number of bytes left in the buffer Buf.
  58.  *
  59.  *    Exit     Returns TRUE iff we returned a line.
  60.  *             Buf      if line was returned, contains that line, zero-
  61.  *                      terminated.
  62.  */
  63. BOOL
  64. GetHeaderLine (Doc, Prefix, Buf, BufLen)
  65.      TypDoc *Doc;
  66.      char *Prefix;
  67.      char *Buf;
  68.      int BufLen;
  69. {
  70.   char *bufptr = Buf;
  71.   TypBlock far *BlockPtr;
  72.   TypLine far *LinePtr;
  73.   unsigned int Offset;
  74.   HANDLE hBlock;
  75.   TypLineID MyLineID;
  76.   int found = FALSE;
  77.  
  78.   TopOfDoc (Doc, &BlockPtr, &LinePtr);
  79.   while (ExtractTextLine (Doc, LinePtr, Buf, BufLen))
  80.     {
  81.  
  82.       /* Is this a blank line signifying the end of the header?      */
  83.  
  84.       if (IsLineBlank (Buf))
  85.     break;
  86.  
  87.       if (CompareStringNoCase (Buf, Prefix, strlen (Prefix)) == 0)
  88.     {
  89.       found = TRUE;
  90.       break;
  91.     }
  92.       if (!NextLine (&BlockPtr, &LinePtr))
  93.     break;
  94.     }
  95.   UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
  96.   return (found);
  97. }
  98.  
  99. /*--- function CreatePostingWnd -----------------------------------------
  100.  *
  101.  *    Create the window for composing the text of a posting,
  102.  *    if it's OK to post.
  103.  *
  104.  *    Entry    Doc      points to the document to which we are posting
  105.  *                      a followup--NULL if it's a new posting.
  106.  *
  107.  *    Exit     Returns the handle of the newly-created window
  108.  *              (zero if failure).
  109.  */
  110.  
  111. HWND
  112. CreatePostingWnd (Doc, DocType)
  113.      TypDoc *Doc;
  114.      int DocType;
  115. {
  116.   int ih;
  117.   BOOL found = FALSE;
  118.   HWND hWnd = 0;
  119.   int width, AveCharWidth;
  120.   HDC hDC;
  121. #ifndef MAC
  122.   TEXTMETRIC tmFontInfo;
  123. #endif
  124.   char *TitlePtr, *WndName;
  125.  
  126.   if (DocType == DOCTYPE_POSTING)
  127.     {
  128.       WndName = "WinVnPost";
  129.       PostDoc = Doc;
  130.       if (Doc)
  131.     {
  132.       TitlePtr = "Composing Followup Article";
  133.     }
  134.       else
  135.     {
  136.       TitlePtr = "Composing New Article";
  137.     }
  138.       for (ih = 0; !found && ih < MAXPOSTWNDS; ih++)
  139.     {
  140.       if (!hWndPosts[ih])
  141.         {
  142.           found = TRUE;
  143.           break;
  144.         }
  145.     }
  146.     }
  147.   else
  148.     {
  149.       WndName = "WinVnMail";
  150.       MailDoc = Doc;
  151.       if (Doc)
  152.     {
  153.       TitlePtr = "Composing Reply Message";
  154.     }
  155.       else
  156.     {
  157.       TitlePtr = "Composing New Mail Message";
  158.     }
  159.       for (ih = 0; !found && ih < MAXMAILWNDS; ih++)
  160.     {
  161.       if (!hWndMails[ih])
  162.         {
  163.           found = TRUE;
  164.           break;
  165.         }
  166.     }
  167.     }
  168.   if (found && AuthenticatePosting ())
  169.     {
  170. #ifndef MAC
  171.       hDC = GetDC (hWndConf);
  172.       GetTextMetrics (hDC, (LPTEXTMETRIC) & tmFontInfo);
  173.       AveCharWidth = tmFontInfo.tmAveCharWidth;
  174.       ReleaseDC (hWndConf, hDC);
  175.  
  176.       if (xScreen > 78 * AveCharWidth)
  177.     {
  178.       width = 78 * AveCharWidth;
  179.     }
  180.       else
  181.     {
  182.       width = xScreen - 2 * AveCharWidth;
  183.     }
  184. #else
  185.       width = xScreen - 20;
  186. #endif
  187.  
  188.       hWnd = CreateWindow (WndName,
  189.                TitlePtr,
  190.                WS_OVERLAPPEDWINDOW /* | WS_VSCROLL */ ,
  191.                ih * CharWidth,    /* Initial X pos */
  192.                (int) (yScreen * 3 / 8) + (1 + ih) * LineHeight,    /* Initial Y pos */
  193.                (int) width,    /* Initial X Width */
  194.                (int) (yScreen * 5 / 8) - (2 * LineHeight),    /* Initial Y height */
  195.                NULL,
  196.                NULL,
  197.                hInst,
  198.                NULL);
  199.  
  200.       if (hWnd)
  201.     {
  202. #ifndef MAC
  203.       ShowWindow (hWnd, SW_SHOWNORMAL);
  204. #else
  205.       MyShowWindow (hWnd, SW_SHOWNORMAL);
  206. #endif
  207.       UpdateWindow (hWnd);
  208.     }
  209.     }
  210.   return (hWnd);
  211. }
  212.  
  213.  
  214. /*--- function CreatePostingText ------------------------------------------
  215.  *
  216.  *    Create the text of the skeleton article to be edited by
  217.  *    the user before posting.   Display that text in an edit window.
  218.  */
  219. BOOL
  220. CreatePostingText (Doc, hWndPost, hWndEdit, DocType)
  221.      TypDoc *Doc;
  222.      HWND hWndPost;
  223.      HWND hWndEdit;
  224.      int DocType;
  225. {
  226.   long int BytesLeft;
  227.   char far *lpTextBuffer;
  228.   char far *lpCurPtr;
  229.   HANDLE hTextBuffer;
  230.   BOOL gotline;
  231.   char line[MAXHEADERLINE];
  232.   int ifunc;
  233.   int nLines;
  234.   long lParam;
  235.   int RefCount;
  236.   BOOL found;
  237.   BOOL (**HeaderFuncs) (TypDoc * Doc, char *Buf, long int BufLen);
  238. #ifdef MAC
  239.   long int textLength;
  240.   TEHandle TEH;
  241.   int ih;
  242.   Rect viewRect, destRect;
  243. #endif
  244.  
  245.   if (DocType == DOCTYPE_POSTING)
  246.     {
  247.       HeaderFuncs = PostHeaderFuncs;
  248.     }
  249.   else
  250.     {
  251.       HeaderFuncs = MailHeaderFuncs;
  252.     }
  253.  
  254.   /* Compute the number of bytes we need to hold a straight ASCII representation
  255.    * of the initial text of the reply, and allocate a buffer of that size.
  256.    */
  257.   found = 0;
  258.   if (Doc)
  259.     {
  260.       BytesLeft = (2 + NumBlocksInDoc (Doc)) * Doc->BlockSize;
  261.     }
  262.   else
  263.     {
  264.       BytesLeft = 3000;
  265.     }
  266.   if (NULL == (hTextBuffer = GlobalAlloc (GHND, (DWORD) BytesLeft)))
  267.     {
  268.       MessageBox (hWndPost, "Cannot allocate memory for text", "", MB_OK);
  269.       return FALSE;
  270.     }
  271.  
  272.   lpCurPtr = lpTextBuffer = GlobalLock (hTextBuffer);
  273.  
  274.   for (ifunc = 0; HeaderFuncs[ifunc]; ifunc++)
  275.     {
  276.       gotline = (HeaderFuncs[ifunc]) (Doc, line, (long int) MAXHEADERLINE);
  277.       if (gotline)
  278.     {
  279.       AppendTextToEditBuf (line, &lpCurPtr, &BytesLeft);
  280.     }
  281.     }
  282.   MakeArtBody (Doc, &lpCurPtr, &BytesLeft, DocType);
  283.  
  284.   /*  Set the edit window text to this skeleton article.            */
  285.  
  286. #ifndef MAC
  287.   SetWindowText (hWndEdit, lpTextBuffer);
  288. #else
  289.   viewRect = hWndPost->portRect;
  290.   viewRect.right -= SBarWidth;
  291.   viewRect.bottom -= SBarWidth;
  292.   destRect = viewRect;
  293.   destRect.left = 3;
  294.  
  295.   SetPort (hWndPost);
  296.   TEH = TENew (&destRect, &viewRect);
  297.   TEHCurrent = TEH;
  298.   (*TEH)->crOnly = -1;
  299.   textLength = lstrlen (lpTextBuffer);
  300.   TESetText (lpTextBuffer, textLength, TEH);
  301.   SetView (hWndPost);
  302.   ShowSelect (hWndPost);
  303.   TEUpdate (&destRect, TEH);
  304.  
  305.   for (ih = 0, found = FALSE; !found && ih < MAXPOSTWNDS; ih++)
  306.     {
  307.       if (hWndPosts[ih] == hWndPost)
  308.     {
  309.       TEHPosts[ih] = TEH;
  310.       found = TRUE;
  311.       break;
  312.     }
  313.     }
  314.   /* mrr add here */
  315. #endif
  316.   GlobalUnlock (hTextBuffer);
  317.   GlobalFree (hTextBuffer);
  318. #if 0
  319.   strcpy (mesbuf, "Winc - Viewing ");
  320.   strncat (mesbuf, NewMemos[imemo], MAXMEMONAME);
  321.   SetWindowText (hWnd, mesbuf);
  322. #endif
  323. #ifndef MAC
  324.   nLines = (int) SendMessage (hWndEdit, EM_GETLINECOUNT, 0, 0L);
  325.   lParam = (long) ((long) nLines);
  326. /* while(nLines--) SendMessage(hWndEdit,WM_KEYDOWN,VK_DOWN,0L); */
  327. #endif
  328.   return TRUE;
  329. }
  330.  
  331. /*--- functions MakeArtHeaderXXXXX ---------------------------------------
  332.  *
  333.  *   Functions with names of the form MakeArtHeaderXxxxxx are all called
  334.  *   the same way and have similar purposes.  They are called to
  335.  *   create and return a line of text that will become a line in
  336.  *   the header of an article to be posted.  The source of
  337.  *   this information varies; it may be taken from an article
  338.  *   being replied to, it may be taken from a configuration file,
  339.  *   read from the system clock, etc.
  340.  *
  341.  *    Entry    Doc      points to a document containing an article
  342.  *                      being replied to; NULL if we're not replying
  343.  *                      to an article.
  344.  *             BufLen   is the length of the output buffer.
  345.  *
  346.  *    Exit     Returns TRUE iff we returned a line.
  347.  *             Buf      contains the line, if any, terminated by a
  348.  *                      zero byte.
  349.  */
  350.  
  351. /*--- function MakeArtHeaderSubject -------------------------------------
  352.  *
  353.  *    Returned "Subject:" line is blank if no previous Subject: line
  354.  *    could be found.  Otherwise, it is "Subject: Re: <previous subject>".
  355.  *    If the article being replied to had a subject already starting
  356.  *    with "Re:", the "Re:" is not repeated.
  357.  */
  358.  
  359. BOOL
  360. MakeArtHeaderSubject (Doc, Buf, BufLen)
  361.      TypDoc *Doc;
  362.      char *Buf;
  363.      long int BufLen;
  364. {
  365.   char HeadLine[MAXHEADERLINE];
  366.   BOOL gotline;
  367.   char *outptr = Buf;
  368.   char *headptr = HeadLine;
  369.  
  370.   CopyBuf ("Subject: ", &outptr, &BufLen);
  371.   if (Doc)
  372.     {
  373.       gotline = GetHeaderLine (Doc, "Subject:", HeadLine, MAXHEADERLINE);
  374.       if (gotline)
  375.     {
  376.       NextToken (&headptr);
  377.       if (CompareStringNoCase (headptr, "Re:", 3) != 0)
  378.         {
  379.           CopyBuf ("Re: ", &outptr, &BufLen);
  380.         }
  381.       CopyBuf (headptr, &outptr, &BufLen);
  382.     }
  383.     else
  384.     {
  385.       DialogBox (hInst, "WinVnSubject", Doc->hDocWnd, lpfnWinVnSubjectDlg);
  386.       CopyBuf (SubjectString, &outptr, &BufLen);
  387.     }
  388.     }
  389.     else
  390.     {
  391.       DialogBox (hInst, "WinVnSubject", hWndConf, lpfnWinVnSubjectDlg);
  392.       CopyBuf (SubjectString, &outptr, &BufLen);
  393.     }
  394.   return (TRUE);
  395. }
  396.  
  397. #if 0
  398. /*--- function MakeArtHeaderMessageID ----------------------------------
  399.  *
  400.  *    Returned "Message-ID:" line is computed from the time and
  401.  *    the ServerName (from Windows profile file).  This needs to
  402.  *    be improved.
  403.  */
  404. BOOL
  405. MakeArtHeaderMessageID (Doc, Buf, BufLen)
  406.      TypDoc *Doc;
  407.      char *Buf;
  408.      long int BufLen;
  409. {
  410. #define MAXSERVERNAME 32
  411.   char ServerName[MAXSERVERNAME];
  412.  
  413.   GetPrivateProfileString (szAppName, "ServerName", "titan.ksc.nasa.gov",
  414.             ServerName, MAXSERVERNAME, szAppProFile);
  415.  
  416.   sprintf (Buf, "Message-ID: <%ld@%s>", time ((time_t *) NULL), ServerName);
  417.   return TRUE;
  418. }
  419.  
  420. #endif
  421.  
  422. /*--- function MakeArtHeaderFrom ----------------------------------
  423.  *
  424.  *  Returned "From:" is taken from Windows profile entries.
  425.  */
  426. BOOL
  427. MakeArtHeaderFrom (Doc, Buf, BufLen)
  428.      TypDoc *Doc;
  429.      char *Buf;
  430.      long int BufLen;
  431. {
  432.   char *outptr = Buf;
  433.  
  434.   CopyBuf ("From: ", &outptr, &BufLen);
  435.   if (MailAddress[0])
  436.     {
  437.       CopyBuf (MailAddress, &outptr, &BufLen);
  438.     }
  439.   else
  440.     {
  441.       CopyBuf ("<Unknown>", &outptr, &BufLen);
  442.     }
  443.   if (UserName[0])
  444.     {
  445.       CopyBuf (" (", &outptr, &BufLen);
  446.       CopyBuf (UserName, &outptr, &BufLen);
  447.       CopyBuf (")", &outptr, &BufLen);
  448.     }
  449.  
  450.   return TRUE;
  451. }
  452.  
  453. /*--- function MakeArtHeaderTo ----------------------------------
  454.  *
  455.  *  Simply returns a blank "To:" line.
  456.  */
  457. BOOL
  458. MakeArtHeaderTo (Doc, Buf, BufLen)
  459.      TypDoc *Doc;
  460.      char *Buf;
  461.      long int BufLen;
  462. {
  463.   char HeadLine[MAXHEADERLINE];
  464.   char *outptr = Buf, *cptr = HeadLine;
  465.   BOOL gotwho;
  466.  
  467.   CopyBuf ("To: ", &outptr, &BufLen);
  468.   if (Doc)
  469.     {
  470.       gotwho = GetHeaderLine (Doc, "Reply-To:", HeadLine, MAXHEADERLINE);
  471.       if (!gotwho)
  472.     {
  473.       gotwho = GetHeaderLine (Doc, "From:", HeadLine, MAXHEADERLINE);
  474.     }
  475.       if (gotwho)
  476.     {
  477.       NextToken (&cptr);
  478.       while (*cptr && *cptr != ' ')
  479.         {
  480.           *(outptr++) = *(cptr++);
  481.         }
  482.       *outptr = '\0';
  483.     }
  484.     }
  485.  
  486.   return TRUE;
  487. }
  488.  
  489. /*--- function MakeArtHeaderOrganization ----------------------------------
  490.  *
  491.  *    Returned "Organization:" line is gotten from the Windows
  492.  *    profile file.
  493.  */
  494. BOOL
  495. MakeArtHeaderOrganization (Doc, Buf, BufLen)
  496.      TypDoc *Doc;
  497.      char *Buf;
  498.      long int BufLen;
  499. {
  500.   char *outptr = Buf;
  501.  
  502.   if (Organization[0])
  503.     {
  504.       CopyBuf ("Organization: ", &outptr, &BufLen);
  505.       CopyBuf (Organization, &outptr, &BufLen);
  506.       return (TRUE);
  507.     }
  508.  
  509.   return FALSE;
  510. }
  511.  
  512. /*--- function MakeArtHeaderNewsreader ----------------------------------
  513.  *
  514.  *    Returned "Newsreader: " line is simply a constant.
  515.  */
  516. BOOL
  517. MakeArtHeaderNewsreader (Doc, Buf, BufLen)
  518.      TypDoc *Doc;
  519.      char *Buf;
  520.      long int BufLen;
  521. {
  522.   char *outptr = Buf;
  523.  
  524.   CopyBuf ("Newsreader: ", &outptr, &BufLen);
  525.   CopyBuf ("MS Windows ", &outptr, &BufLen);
  526.   CopyBuf (szAppName, &outptr, &BufLen);
  527. /* easier than examining this closely */
  528.   CopyBuf ("\r", &outptr , &BufLen);
  529.   return (TRUE);
  530.  
  531. }
  532.  
  533. #if 0
  534. /*--- function MakeArtHeaderDate ----------------------------------
  535.  *
  536.  *    Returned "Date:" line is computed from operating system time.
  537.  *    Be sure to set the TZ environment variable correctly for
  538.  *    "grtime" to work properly.  Typical setting:  SET TZ=EST5
  539.  */
  540. BOOL
  541. MakeArtHeaderDate (Doc, Buf, BufLen)
  542.      TypDoc *Doc;
  543.      char *Buf;
  544.      long int BufLen;
  545. {
  546.   struct tm *timeptr;
  547.   time_t curtime;
  548.  
  549.   curtime = time ((time_t *) NULL);
  550.   timeptr = gmtime (&curtime);
  551.   sprintf (Buf, "Date: %.4d-%.2d-%.2d %.2d:%.2d GMT", timeptr->tm_year + 1900,
  552.   timeptr->tm_mon + 1, timeptr->tm_mday, timeptr->tm_hour, timeptr->tm_min);
  553.   return TRUE;
  554. }
  555.  
  556. #endif
  557.  
  558. /*--- function MakeArtHeaderReferences -----------------------------------
  559.  *
  560.  *  Returned "References:" line contains all the previous article's
  561.  *  References (if any), plus its Message-ID (if any).
  562.  */
  563. BOOL
  564. MakeArtHeaderReferences (Doc, Buf, BufLen)
  565.      TypDoc *Doc;
  566.      char *Buf;
  567.      long int BufLen;
  568. {
  569.   char HeadLine[MAXHEADERLINE];
  570.   BOOL gotrefs;
  571.   BOOL gotmesID;
  572.   char *outptr = Buf;
  573.   char *headptr = HeadLine;
  574.  
  575.  
  576.   if (Doc)
  577.     {
  578.       gotrefs = GetHeaderLine (Doc, "References:", HeadLine, MAXHEADERLINE);
  579.       if (gotrefs)
  580.     {
  581.       CopyBuf (HeadLine, &outptr, &BufLen);
  582.       CopyBuf (" ", &outptr, &BufLen);
  583.     }
  584.       gotmesID = GetHeaderLine (Doc, "Message-ID:", HeadLine, MAXHEADERLINE);
  585.       if (gotmesID)
  586.     {
  587.       if (!gotrefs)
  588.         {
  589.           CopyBuf ("References: ", &outptr, &BufLen);
  590.         }
  591.       NextToken (&headptr);
  592.       CopyBuf (headptr, &outptr, &BufLen);
  593.     }
  594.       if (gotrefs || gotmesID)
  595.     return (TRUE);
  596.     }
  597.   return FALSE;
  598. }
  599.  
  600. /*--- function MakeArtHeaderNewsgroups -----------------------------------
  601.  *
  602.  *  Returned "Newsgroups:" line is simply a copy of previous article's.
  603.  */
  604. BOOL
  605. MakeArtHeaderNewsgroups (Doc, Buf, BufLen)
  606.      TypDoc *Doc;
  607.      char *Buf;
  608.      long int BufLen;
  609. {
  610.   char HeadLine[MAXHEADERLINE];
  611.   BOOL gotnews = FALSE;
  612.   char *outptr = Buf;
  613.  
  614.   if (Doc)
  615.     {
  616.       gotnews = GetHeaderLine (Doc, "Newsgroups:", HeadLine, MAXHEADERLINE);
  617.       if (gotnews)
  618.     {
  619.       CopyBuf (HeadLine, &outptr, &BufLen);
  620.     }
  621.     }
  622.   if (!gotnews)
  623.     {
  624.       CopyBuf ("Newsgroups: ", &outptr, &BufLen);
  625.       CopyBuf (NewsgroupsPtr, &outptr, &BufLen);
  626.     }
  627.   return TRUE;
  628. }
  629.  
  630. /*--- function MakeArtBody ----------------------------------------------
  631.  *
  632.  *    Make the body of the article.  This is null if there's no article
  633.  *    to reply to, else it's text of the form:
  634.  *    In article <Message-ID>, <user> says:
  635.  *    >line 1
  636.  *    >line 2
  637.  *    > .....
  638.  *
  639.  *    Entry    Doc      points to the article being replied to, else
  640.  *                      NULL if none.
  641.  *             left     is the number of bytes left in MesBuf.
  642.  *
  643.  *    Exit     MesBuf   contains the added lines, and has been updated
  644.  *                      to point to just after the last added byte.
  645.  *             left     has been decremented appropriately.
  646.  *             Return value is not used, for now.
  647.  */
  648. BOOL 
  649. MakeArtBody (Doc, MesBuf, left, DocType)
  650.      TypDoc *Doc;
  651.      char far **MesBuf;
  652.      long int *left;
  653.      int DocType;
  654. {
  655.   HANDLE hBlock;
  656.   unsigned int Offset;
  657.   TypLineID MyLineID;
  658.   TypBlock far *BlockPtr;
  659.   TypLine far *LinePtr;
  660.   char mesID[MAXHEADERLINE];
  661.   char from[MAXHEADERLINE];
  662.   char line[MAXHEADERLINE];
  663.   BOOL gotmesID, gotfrom;
  664.   char *outptr = line;
  665.   char *fromptr = from;
  666.   char *mesptr = mesID;
  667.  
  668.   AppendTextToEditBuf ("", MesBuf, left);    /* blank line after header */
  669.  
  670.   /* Create the "In message xxx, yyy says:" line.                   */
  671.  
  672.   if (Doc)
  673.     {
  674.       gotmesID = GetHeaderLine (Doc, "Message-ID:", mesID, MAXHEADERLINE);
  675.       if (gotmesID)
  676.     {
  677.       NextToken (&mesptr);
  678.     }
  679.       else
  680.     {
  681.       mesptr = "<Unknown>";
  682.     }
  683.       if (DocType == DOCTYPE_POSTING)
  684.     {
  685.       gotfrom = GetHeaderLine (Doc, "From:", from, MAXHEADERLINE);
  686.       if (gotfrom)
  687.         {
  688.           NextToken (&fromptr);
  689.         }
  690.       else
  691.         {
  692.           fromptr = "<Unknown>";
  693.         }
  694.       sprintf (line, "In article %s, %s says:", mesptr, fromptr);
  695.     }
  696.       else
  697.     {
  698.       sprintf (line, "In article %s, you say:", mesptr);
  699.     }
  700.       AppendTextToEditBuf (line, MesBuf, left);
  701.  
  702.       /* Skip past header of reply document.                            */
  703.  
  704.       TopOfDoc (Doc, &BlockPtr, &LinePtr);
  705.       while (ExtractTextLine (Doc, LinePtr, line, MAXHEADERLINE) &&
  706.          !IsLineBlank (line))
  707.     {
  708.       if (!NextLine (&BlockPtr, &LinePtr))
  709.         break;
  710.     }
  711.  
  712.       /* Copy body of reply document into the body of this article,  */
  713.       /* prepending a ">" to each line.                              */
  714.  
  715.       line[0] = '>';
  716.       while (ExtractTextLine (Doc, LinePtr, line + 1, MAXHEADERLINE - 1))
  717.     {
  718.       AppendTextToEditBuf (line, MesBuf, left);
  719.       if (!NextLine (&BlockPtr, &LinePtr))
  720.         break;
  721.     }
  722.       UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
  723.     }
  724.   return TRUE;
  725. }
  726.  
  727.  
  728. /*--- function CompareStringNoCase -------------------------------------
  729.  *
  730.  *   Compare two strings, case insensitive.
  731.  *
  732.  *    Entry    str1, str2  are two strings to compare.
  733.  *             slen        is the number of characters to compare
  734.  *                         (but stop at a zero byte).
  735.  *
  736.  *    Exit     returns -1 if str1 is earlier in collating sequence,
  737.  *              0 if strings are equal, 1 otherwise
  738.  */
  739. int
  740. CompareStringNoCase (str1, str2, slen)
  741.      char *str1;
  742.      char *str2;
  743.      int slen;
  744. {
  745.   while (slen-- && *str1 && *str2)
  746.     {
  747.       if (_tolower (*str1) < _tolower (*str2))
  748.     {
  749.       return (-1);
  750.     }
  751.       else if (_tolower (*str1) > _tolower (*str2))
  752.     {
  753.       return (1);
  754.     }
  755.       str1++;
  756.       str2++;
  757.     }
  758.   return (0);
  759. }
  760.  
  761. /*--- function CopyBuf -----------------------------------------------
  762.  *
  763.  *    Copy a string into a buffer, being sure not to overrun the
  764.  *    buffer.
  765.  *
  766.  *    Entry    instr    points to the string to copy into the buffer,
  767.  *                      zero-terminated.
  768.  *             buf      is the buffer
  769.  *             left     is the number of bytes left in the buffer
  770.  *    Exit     buf      contains the LWA+1 of the bytes copied into
  771.  *                      the output buffer.  A Zero byte is stored
  772.  *                      into this location.
  773.  *             left     is the number of bytes left in the buffer.
  774.  */
  775.  
  776. void
  777. CopyBuf (instr, buf, left)
  778.      char *instr;
  779.      char **buf;
  780.      long int *left;
  781. {
  782.   while (--(*left) > 1 && *instr)
  783.     {
  784.       *((*buf)++) = *(instr++);
  785.     }
  786.   if (*left > 0)
  787.     **buf = '\0';
  788. }
  789.  
  790. /*--- function NextToken -----------------------------------------------
  791.  *
  792.  *  Position a pointer to the next token in a string.
  793.  *  Delimiters are space and tab.
  794.  *
  795.  *    Entry    cptr     points to a position in a zero-terminated string.
  796.  *
  797.  *    Exit     Returns TRUE iff a next token was found.
  798.  *             cptr     points to the next token, if found--else
  799.  *                      it is unchanged.
  800.  */
  801. BOOL
  802. NextToken (cptr)
  803.      char **cptr;
  804. {
  805.   /* Skip to end of current token, if any.              */
  806.  
  807.   while (**cptr != ' ' && **cptr != '\t' && **cptr)
  808.     (*cptr)++;
  809.  
  810.   /* Skip past white space.                             */
  811.  
  812.   while (**cptr && (**cptr == ' ' || **cptr == '\t'))
  813.     (*cptr)++;
  814.   if (**cptr)
  815.     {
  816.       return (TRUE);
  817.     }
  818.   else
  819.     {
  820.       return (FALSE);
  821.     }
  822. }
  823.  
  824. /*--- function AppendTextToEditBuf ----------------------------------------
  825.  *
  826.  *    Appends a zero-terminated text line to a buffer to be given
  827.  *    to an Edit window.  Used in building messages to be displayed
  828.  *    and edited by an Edit window.
  829.  *
  830.  *    Entry    instr    points to a text line to add.  It is terminated
  831.  *                      by a zero byte and does not end in CR or LF.
  832.  *             left     is the number of characters left in buf.
  833.  *
  834.  *    Exit     buf      contains the line, terminated by CR and LF.
  835.  *                      buf now points to the next available byte.
  836.  *             left     has been decremented as appropriate.
  837.  */
  838. void
  839. AppendTextToEditBuf (instr, buf, left)
  840.      char *instr;
  841.      char far **buf;
  842.      long int *left;
  843. {
  844.   while (--(*left) > 0 && *instr)
  845.     {
  846.       *((*buf)++) = *(instr++);
  847.     }
  848.   if (--(*left) > 0)
  849.     *((*buf)++) = '\r';
  850. #ifndef MAC
  851.   if (--(*left) > 0)
  852.     *((*buf)++) = '\n';
  853. #endif
  854.   if ((*left) > 0)
  855.     **buf = '\0';
  856. }
  857.  
  858. /*--- function IsLineBlank ------------------------------------------------
  859.  *
  860.  *    Determine whether a zero-terminated line is blank.
  861.  *    "Blank" means it contains nothing but spaces and tabs.
  862.  *
  863.  *    Entry    line     points to the line.
  864.  *
  865.  *    Exit     returns TRUE iff the line is blank.
  866.  */
  867. BOOL
  868. IsLineBlank (line)
  869.      char far *line;
  870. {
  871.   while (*line == ' ' || *line == '\t' || *line == '\n')
  872.     line++;
  873.   return (!(*line));
  874. }
  875.  
  876. 
  877.